#include "PieceManager.h"

PieceManager *pieceman;

void storeScreenCoords(){
	double x, y, z;

	GLdouble model_view[16];
	glGetDoublev(GL_MODELVIEW_MATRIX, model_view);

	GLdouble projection[16];
	glGetDoublev(GL_PROJECTION_MATRIX, projection);

	GLint viewport[4];
	glGetIntegerv(GL_VIEWPORT, viewport);

	for(int i = 0; i < 12; i++){
		for(int j = 0; j < 24; j++){
			gluProject(-55+10*i, 0, -115+10*j, model_view, projection, viewport, &x, &y, &z);
			cellCoords[i][j][0] = x;
			cellCoords[i][j][1] = y;
			cellCoords[i][j][2] = z;
		}
	}
}
void moveCamera(){
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	eye[1] = eyeDist*sin(degYZ*(PI/180));
	eye[0] = (eyeDist*cos(degYZ*(PI/180)))*sin(degXZ*(PI/180));
	eye[2] = (eyeDist*cos(degYZ*(PI/180)))*cos(degXZ*(PI/180));

	gluLookAt(eye[0],eye[1],eye[2], lookAt[0],lookAt[1],lookAt[2], 0.0,1.0,0.0);
	storeScreenCoords();

	glutPostRedisplay();
}
void highlightCell(int x, int y, int type){
	if(curCell[0] != -1 && curCell[0] != 10 && !((curCell[0] == 2 || curCell[0] == 3 || curCell[0] == 6 || curCell[0] == 7) && (curCell[1] == 4 || curCell[1] == 5))){
		glPushMatrix();
			glTranslatef(-50 + x*10,.04,-50 + y*10);
			if(type == 0)
				glColor4f(1.0,1.0,0,.4);
			else if(type == 1)
				glColor4f(0.0,1.0,0,.4);
			else if(type == 2)
				glColor4f(1.0,0.0,0,.4);
			glPushMatrix();
				glBegin(GL_QUADS);
					glVertex3f(0, .02, 1);
					glVertex3f(1, .02, 1);
					glVertex3f(1, .02, 9);
					glVertex3f(0, .02, 9);
				glEnd();
				glBegin(GL_QUADS);
					glVertex3f(9, .02, 1);
					glVertex3f(10, .02, 1);
					glVertex3f(10, .02, 9);
					glVertex3f(9, .02, 9);
				glEnd();
				glBegin(GL_QUADS);
					glVertex3f(0, .02, 0);
					glVertex3f(10, .02, 0);
					glVertex3f(10, .02, 1);
					glVertex3f(0, .02, 1);
				glEnd();	
				glBegin(GL_QUADS);
					glVertex3f(0, .02, 9);
					glVertex3f(10, .02, 9);
					glVertex3f(10, .02, 10);
					glVertex3f(0, .02, 10);
				glEnd();
			glPopMatrix();
		glPopMatrix();
	}
}
void drawText(string msg, float xpos, float ypos){
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(0,1,0,1,-1,1);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	glColor3f(1, 1, 1);
    	glRasterPos3f(xpos,ypos,0);
    	for(int i = 0; i < msg.length(); i++)
    		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24 ,msg[i]);
	
	glPopMatrix();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
}
void drawMenu(){
	glColor4f(1.0,1.0,1.0,1.0);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, menuText);
	glBegin(GL_QUADS);
		glTexCoord2d(1,1); glVertex3f(1,1,0);
		glTexCoord2d(0,1); glVertex3f(0,1,0);
		glTexCoord2d(0,0); glVertex3f(0,0,0);
		glTexCoord2d(1,0); glVertex3f(1,0,0);
	glEnd();
	glDisable(GL_TEXTURE_2D);
}
void drawPiece(float x, float y, int type, int team, bool highlighted){	
	if(highlighted){
		glColor4f(1.0,1.0,1.0,1.0);
	}
	else{	
		if(team == RED){
			glColor4f(1.0,0.0,0.0,1.0);
		}
		else{
			glColor4f(0.0,0.0,1.0,1.0);
		}
	}
	glPushMatrix();
		glTranslatef(-45+10*x,-.51,-45+10*y);
		if(team == BLUE)
			glRotatef(180,0.0,1.0,0.0);
		glPushMatrix();
			glTranslatef(0,1,0);
			glScalef(9,2,9);
			glutSolidCube(1);
		glPopMatrix();
		glPushMatrix();
			glTranslatef(0,6.5,3.5);
			glScalef(9,9,2);
			glutSolidCube(1);
		glPopMatrix();
		glColor4f(1.0,1.0,1.0,1.0);
		glEnable(GL_TEXTURE_2D);
		if(type != 0)
			glBindTexture(GL_TEXTURE_2D, pieceTexts[type]);
		else
			glBindTexture(GL_TEXTURE_2D, flagTexts[team]);
		glBegin(GL_QUADS);
			glTexCoord2d(1,0); glVertex3f(-4.4, 2.1, 2.45);
			glTexCoord2d(1,1); glVertex3f(-4.4, 10.9, 2.45);
			glTexCoord2d(0,1); glVertex3f(4.4, 10.9, 2.45);
			glTexCoord2d(0,0); glVertex3f(4.4, 2.1, 2.45);
		glEnd();
	glPopMatrix();		
}
void drawHighlights(){
	if(selectedPiece >= 0){
		if(pieceman->status() == SETUP){
			highlightCell((pieceman->getPiece(selectedPiece))->x(), (pieceman->getPiece(selectedPiece))->y(), 0);
			highlightCell(curCell[0], curCell[1], 0);
		}
		else{
			for(int x = 0; x < 10; x++){
				for(int y = 0; y < 10; y++){
					if(potMoves[x][y] == 1)
						highlightCell(x, y, 1);
					else if(potMoves[x][y] == 2)
						highlightCell(x, y, 2);
				}
			}
			highlightCell((pieceman->getPiece(selectedPiece))->x(), (pieceman->getPiece(selectedPiece))->y(), 0);
		}
	}
	else{
		highlightCell(curCell[0], curCell[1], 0);
	}
}
void drawMovingPiece(){
	if(automoving || autoattacking){
		Piece *temp;
		temp = pieceman->getPiece(selectedPiece);
		drawPiece(automove_coords[0][0], automove_coords[0][1], temp->getType(), temp->getTeam(), true);
	}
	else if(selectedPiece >= 0){
		Piece *temp;
		temp = pieceman->getPiece(selectedPiece);
		drawPiece((float) temp->x(), (float) temp->y(), temp->getType(), temp->getTeam(), true);
	}
}
void drawStationaryPieces(){
	vector<vector<int> > on_pieces = pieceman->getOnPieces();
	Piece *temp;
	for(int team = 0; team < 2; team++){
		for(int pos = 0; pos < on_pieces[team].size(); pos++){
			temp = pieceman->getPiece(on_pieces[team][pos]);
			if(selectedPiece != temp->getID()){
				drawPiece((float) temp->x(),(float) temp->y(), temp->getType(), team, false);
			}
		}
	}
	if(pieceman->status() == SETUP){
		vector<vector<int> > off_pieces = pieceman->getOffPieces();
		for(int team = 0; team < 2; team++){
			for(int pos = 0; pos < off_pieces[team].size(); pos++){
				temp = pieceman->getPiece(off_pieces[team][pos]);
				if(selectedPiece != temp->getID()){
					if(team == RED)
						drawPiece((float) temp->x(), (float) temp->y(), temp->getType(), team, false);
					else
						drawPiece((float) temp->x(), (float) temp->y(), temp->getType(), team, false);
				}
			}
		}
	}
}			
void drawBoard(){
	glColor4f(1.0,1.0,1.0,1.0);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, boardText);
	glBegin(GL_QUADS);
		glTexCoord2d(1,1); glVertex3f(50, 0, 50);
		glTexCoord2d(0,1); glVertex3f(-50, 0, 50);
		glTexCoord2d(0,0); glVertex3f(-50, 0, -50);
		glTexCoord2d(1,0); glVertex3f(50, 0, -50);
	glEnd();
	glDisable(GL_TEXTURE_2D);
	glColor4f(0.25,0.0,0.0,1.0);
	glPushMatrix();
		glTranslatef(0,-.51,0);
		glScalef(105, 1, 105);
		glutSolidCube(1);
	glPopMatrix();
	glColor4f(0.0,0.0,0.0,1.0);
	for(int num = 0; num < 11; num++){
		glPushMatrix();
			glTranslatef(-50+10*num,0,0);
			glScalef(.3, .3, 100);
			glutSolidCube(1);
		glPopMatrix();
	}
	for(int num = 0; num < 11; num++){
		glPushMatrix();
			glTranslatef(0,0,-50+10*num);
			glScalef(100, .3, .3);
			glutSolidCube(1);
		glPopMatrix();
	}
}
void mouseFunction(int key, int state, int mx, int my){
	switch(key){
		case GLUT_LEFT_BUTTON :
			if(whichButtonDown == BNONE){
				if(selectedPiece >= 0){
					automove_coords[1][0] = (float) curCell[0];
					automove_coords[1][1] = (float) curCell[1];
					if(pieceman->status() == SETUP){
						if(focusedPiece == -1){
							pieceman->placePiece(curCell[0],curCell[1],selectedPiece);
							selectedPiece = -1;
						}
					}
					else{							
						int temp = pieceman->movePiece(curCell[0],curCell[1],selectedPiece);
						if(temp == 1 || temp == 2){
							currentTeam = (currentTeam+1)%2;
							automoving = true;
						}	
						else
							selectedPiece = -1;
					}								
				}
				else{
					if(focusedPiece >= 0 && (pieceman->getPiece(focusedPiece))->getTeam() == currentTeam){
						automove_coords[0][0] = (float) curCell[0];
						automove_coords[0][1] = (float) curCell[1];
						selectedPiece = focusedPiece;
						if(pieceman->status() != SETUP)
							potMoves = pieceman->getPotMoves(selectedPiece);
					}
				}
			}	
			whichButtonDown = state == GLUT_DOWN ? BLEFT : BNONE;
			break;
		case GLUT_MIDDLE_BUTTON :
			whichButtonDown = state == GLUT_DOWN ? BMIDDLE : BNONE;
			break;
		case GLUT_RIGHT_BUTTON :
			whichButtonDown = state == GLUT_DOWN ? BRIGHT : BNONE;
			break;
		default:
			// should never get here
			break;
	}
}
vector<int> getCell(int mx, int my){
	double minDist = 2000, dist, dx, dy, dz;
	vector<int> cell_coord(2);

	for(int i = 0; i < 12; i++){
		for(int j = 0; j < 24; j++){
			dx = (mx - cellCoords[i][j][0]);
			dy = ((600 - my) - cellCoords[i][j][1]);
			dz = (cellCoords[i][j][2] - 0);
			dist = sqrt(dx*dx + dy*dy + dz*dz);
			if(dist < minDist){
				cell_coord[0] = i;
				cell_coord[1] = j;				
				minDist = dist;
			}
		}
	}
	cell_coord[0] -= 1;
	cell_coord[1] -= 7;
	return cell_coord;
}
void passiveMotionFunction(int mx, int my){
	vector<int> cell = getCell(mx, my);
	if(curCell[0] != cell[0] || curCell[1] != cell[1]){
		if(selectedPiece >= 0 && pieceman->status() == SETUP){
			if(currentTeam == RED){
				if(cell[1] >= 4)
					cell[1] = 3;
			}
			else{
				if(cell[1] < 6)
					cell[1] = 6;
			}
		}	
		curCell[0] = cell[0]; curCell[1] = cell[1];
		focusedPiece = pieceman->getPiece(curCell[0],curCell[1]);
	}
}
void keyboard (unsigned char key, int mx, int my){
	if (key == '=')
		eyeDist -= 1;
	else if(key == '-')
		eyeDist +=  1;
	moveCamera();
	glutPostRedisplay();
}
void special (int key, int x, int y){
	if (key == GLUT_KEY_RIGHT)
		degXZ += 2.0;
	else if (key == GLUT_KEY_LEFT)
		degXZ -= 2.0;
	else if (key == GLUT_KEY_UP)
		degYZ += 2.0;
	else if (key == GLUT_KEY_DOWN)
		degYZ -= 2.0;
	moveCamera();
	glutPostRedisplay();
}
void timer(int n){
	if(automoving){
		if(automove_coords[0][0] != automove_coords[1][0]){
			if(automove_coords[0][0] > automove_coords[1][0]){
				automove_coords[0][0] -= step;
				if(automove_coords[0][0] < automove_coords[1][0])
					automove_coords[0][0] = automove_coords[1][0];
			}
			else if(automove_coords[0][0] < automove_coords[1][0]){
				automove_coords[0][0] += step;
				if(automove_coords[0][0] > automove_coords[1][0])
					automove_coords[0][0] = automove_coords[1][0];
			}
		}
		else if(automove_coords[0][1] != automove_coords[1][1]){
			if(automove_coords[0][1] > automove_coords[1][1]){
				automove_coords[0][1] -= step;
				if(automove_coords[0][1] < automove_coords[1][1])
					automove_coords[0][1] = automove_coords[1][1];
			}
			else if(automove_coords[0][1] < automove_coords[1][1]){
				automove_coords[0][1] += step;
				if(automove_coords[0][1] > automove_coords[1][1])
					automove_coords[0][1] = automove_coords[1][1];
			}
		}
		else{
			if(pieceman->status() == P1WON || pieceman->status() == P2WON){
				cout << "WINNER!" << "\n";
				exit(0);
			} 
			automoving = false;
			selectedPiece = -1;
		}
	}
	glutTimerFunc(20,timer,1);
	glutPostRedisplay();	
}
void initTex(){
	boardText = SOIL_load_OGL_texture("board.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	flagTexts[RED] = SOIL_load_OGL_texture("flag_red.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	flagTexts[BLUE] = SOIL_load_OGL_texture("flag_blue.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[1] = SOIL_load_OGL_texture("spy.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[2] = SOIL_load_OGL_texture("scout.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[3] = SOIL_load_OGL_texture("miner.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[4] = SOIL_load_OGL_texture("sergeant.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[5] = SOIL_load_OGL_texture("lieutenant.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[6] = SOIL_load_OGL_texture("captain.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[7] = SOIL_load_OGL_texture("major.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[8] = SOIL_load_OGL_texture("colonel.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[9] = SOIL_load_OGL_texture("general.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[10] = SOIL_load_OGL_texture("marshal.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
	pieceTexts[11] = SOIL_load_OGL_texture("bomb.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
}
void initLightsMats(){
	GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
	
	glEnable(GL_LIGHTING);

	glLightfv(GL_LIGHT0,GL_AMBIENT, light_ambient[0]);
	glLightfv(GL_LIGHT0,GL_DIFFUSE, light_diffuse[0]);
	glLightfv(GL_LIGHT0,GL_SPECULAR, light_specular[0]);
	glLightfv(GL_LIGHT0,GL_POSITION,light_posit[0]);
	glEnable(GL_LIGHT0);
	
	glLightfv(GL_LIGHT1,GL_AMBIENT, light_ambient[1]);
	glLightfv(GL_LIGHT1,GL_DIFFUSE, light_diffuse[1]);
	glLightfv(GL_LIGHT1,GL_SPECULAR, light_specular[1]);
	glLightfv(GL_LIGHT1,GL_POSITION,light_posit[1]);
	glEnable(GL_LIGHT1);

	glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
	glEnable(GL_COLOR_MATERIAL);
	
	glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
	glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
	glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
	glMaterialf(GL_FRONT,GL_SHININESS,mat_shine);
}
